<?php
//This is a proof of concept to show how to access the perfSONAR NC RRD MA through the NMWG protocol.
//It is not meant to be production quality code and we do NOT claim full NMWG compliance.
//We have implemented enough features so that the implementation can be used with perfSONAR UI.
//Since no proper wsdl file has been defined for perfSONAR we just process the SOAP messages manually
//and we do not implement full SOAP support.

$maid=1;

require("perfsonarnc.cfg.php");
//Connect to server
if (($socket=pfsockopen("unix://".$cfg['socket'])) === false)
die("pfsockopen() failed\n");
if(ftell($socket)>0) {
	fclose($socket);
	if (($socket=pfsockopen("unix://".$cfg['socket'])) === false)
	die("pfsockopen() failed\n");
}

//hello message
while(true) {
	if(($str=fgets($socket)) == false)
	die("Error reading hello message\n");
	if(rtrim($str)=="]]>]]>")
	break;
}
fputs($socket,"<?xml version='1.0'?>
<hello xmlns='urn:ietf:params:xml:ns:netconf:base:1.0'>
  <capabilities>
   <capability>urn:ietf:params:xml:ns:netconf:base:1.0</capability>
   <capability>urn:ietf:params:netconf:capability:xpath:1.0</capability>
  </capabilities>
</hello>
]]>]]>");

//Read query
$in=fopen("php://input","r");
$xml="";
while($str=fgets($in)) {
	$xml.=$str;
	if(preg_match("/\/soapenv:envelope/",strtolower($str)))
	break;
}


//Parse query
$dom=new domDocument();
if(!$dom->loadXML($xml))
die("Could not load XML request: $xml");
$xp=new DOMXPath($dom);
$xp->registerNamespace("nmwg","http://ggf.org/ns/nmwg/base/2.0/");
$xp->registerNamespace("nmwgt","http://ggf.org/ns/nmwg/topology/2.0/");
$xp->registerNamespace("netutil","http://ggf.org/ns/nmwg/characteristic/utilization/2.0/");
$xp->registerNamespace("select","http://ggf.org/ns/nmwg/ops/select/2.0/");
if($xp->query("//nmwg:message/@type[.='EchoRequest']")->length>0 and $xp->query("//nmwg:eventType[.='http://schemas.perfsonar.net/tools/admin/echo/2.0']")->length>0)
echoResponse($xp);
elseif($xp->query("//nmwg:message/@type[.='MetadataKeyRequest']")->length>0 and $xp->query("//nmwg:eventType[.='http://ggf.org/ns/nmwg/characteristic/utilization/2.0']")->length>0)
metadataResponse($xp,$socket);
elseif($xp->query("//nmwg:message/@type[.='SetupDataRequest']")->length>0 and $xp->query("//nmwg:eventType[.='http://ggf.org/ns/nmwg/characteristic/utilization/2.0']")->length>0)
dataResponse($dom,$xp,$socket);
else
print "Message not supported\n";


function echoResponse($xp) {
	$id=getMsgID($xp);
	print soapPre()."<nmwg:message xmlns:nmwg='http://ggf.org/ns/nmwg/base/2.0/' id='Resp_$id' messageIdRef='$id' type='EchoResponse'><nmwg:metadata id='result-code'><nmwg:eventType>echo/success</nmwg:eventType></nmwg:metadata><nmwg:data id='result-code-description' metadataIdRef='result-code'><nmwgr:datum xmlns:nmwgr='http://ggf.org/ns/nmwg/result/2.0/'>This is the success echo response from the service.</nmwgr:datum></nmwg:data></nmwg:message>".soapPost();
}

function metadataResponse($xp,$socket) {
	$interfaces=$xp->query("//nmwgt:interface");
	$filter="";
	foreach($interfaces as $int) {
		if($int->childNodes->length>0)
		print "Not supported yet\n";
	}
	if($filter=="") {
		$obspoints=query($socket,"//pn:ma[pn:name='rrdma']/pn:dataSources/pn:dataSource/pn:obsPoints/pn:obsPoint");
		$xsl=new DOMDocument();
		$xsl->load("xslt/metadata.xslt");
		$xml=new DOMDocument();
		$xml->loadXML($obspoints);
		$proc=new XSLTProcessor();
		$proc->importStylesheet($xsl);
		print $proc->transformToXML($xml);
	} else print "Not supported\n";
}

function parseObspoints($xp) {
	$obs=$xp->query("//nmwg:metadata[nmwg:eventType='http://ggf.org/ns/nmwg/characteristic/utilization/2.0']/netutil:subject/nmwgt:interface");
	$filter="";
	$or="";
	foreach($obs as $o) {
		if(!$o->hasChildNodes())
		return "//pn:obsPoint";
		$filter.="$or (pn:name='".$o->getElementsByTagName("ifName")->item(0)->textContent."' and pn:hostname='".$o->getElementsByTagName("hostName")->item(0)->textContent."' and pn:direction='".$o->getElementsByTagName("direction")->item(0)->textContent."')";
		$or=" or ";
	}
	return "//pn:obsPoint[$filter]";
}

function getParameter($xp,$name) {
	$value=$xp->query("//nmwg:metadata[nmwg:eventType='http://ggf.org/ns/nmwg/ops/select/2.0']/select:parameters/nmwg:parameter[@name[.='$name']]");
	return $value->item(0)->textContent;
}

function dataResponse($dom,$xp,$socket) {
	global $maid,$cfg;
	$id=getMsgID($xp);
	$name="query".rand();

	$obs=parseObspoints($xp);
	$resolution=getParameter($xp,"resolution");
	$start=getParameter($xp,"startTime");
	$stop=getParameter($xp,"endTime");
	
	$write='<?xml version="1.0"?>
<rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="1">
<edit-config>
<target><running/></target>
<config>
<perfSONARNC xmlns="http://stager.uninett.no/perfsonarnc/1.0">
        <measurementArchivesAndQueries>
        <queries>
        <query>
        <name>'.$name.'</name>
         <ma>'.$maid.'</ma>
          <dataSource>'.$cfg['nmwg_source'].'</dataSource>      
                <report>rrd</report>
                <type>singleTable</type>
                <view>standard</view>
                <obsPoints>
                  <query>'.$obs.'/pn:id</query>
                </obsPoints>
                <timePeriods>
                 <start>'.$start.'</start>
                 <stop>'.$stop.'</stop>
                 <resolution>'.$resolution.'</resolution>
				</timePeriods>
                <limit/>
                <sort/>
              </query>
            </queries>
      </measurementArchivesAndQueries>
     </perfSONARNC>
   </config>
 </edit-config>
 </rpc>';

	//Send report query to server and read the result
	fputs($socket,$write."\n]]>]]>\n");
	$ret="";
	while(true) {
		if(($str=fgets($socket)) == false)
		die("Error reading message\n");
		if(rtrim($str)=="]]>]]>")
		break;
		$ret.=$str;
	}

	$data=query($socket,"$obs|/nc:data/pn:perfSONARNC/pn:measurementArchivesAndQueries/pn:queries/pn:query[pn:name='$name' and pn:ma='$maid']/pn:result");
	$xsl=new DOMDocument();
	$xsl->load("xslt/data.xslt");
	$xml=new DOMDocument();
	$xml->loadXML($data);
	$proc=new XSLTProcessor();
	$proc->importStylesheet($xsl);
	print $proc->transformToXML($xml);


}

function query($socket,$query) {
	$dom = new DomDocument;
	$rpc=$dom->createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0","rpc");
	$rpc->appendChild(_addAttr($dom,"message-id",1));
	$dom->appendChild($rpc);
	$get=$dom->createElement("get");
	$rpc->appendChild($get);
	$source=$dom->createElement("source");
	$get->appendChild($source);
	$source->appendChild($dom->createElement("running"));
	$filter=$dom->createElement("filter");
	$filter->appendChild(_addAttr($dom,"type","xpath"));
	$filter->appendChild(_addAttr($dom,"select",$query));
	$get->appendChild($filter);
	fputs($socket,$dom->saveXML()."\n]]>]]>\n");
	$ret="";
	while(true) {
		if(($str=fgets($socket)) == false)
		die("Error reading message\n");
		if(rtrim($str)=="]]>]]>")
		break;
		$ret.=$str;
	}
	return $ret;
}

function _addAttr($dom,$name,$value) {
	$attr=$dom->createAttribute($name);
	$attr->appendChild($dom->createTextNode($value));
	return $attr;
}

function getMsgID($xp) {
	$res=$xp->query("//nmwg:message/@id");
	return $res->item(0)->textContent;
}

function soapPre() {
	return "<?xml version='1.0' encoding='utf-8'?>\n<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/'><soapenv:Body>";
}

function soapPost() {
	return '</soapenv:Body></soapenv:Envelope>';
}
?>